package com.ler.yrmall.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ler.yrmall.coupon.api.CouponApi;
import com.ler.yrmall.coupon.dto.CouponDTO;
import com.ler.yrmall.coupon.dto.SeckillOrderDTO;
import com.ler.yrmall.cart.api.CartApi;
import com.ler.yrmall.cart.dto.CartDTO;
import com.ler.yrmall.cart.dto.CartItemDTO;
import com.ler.yrmall.member.api.MemberApi;
import com.ler.yrmall.member.dto.MemberReceiveAddressDTO;
import com.ler.yrmall.basic.Form;
import com.ler.yrmall.basic.Result;
import com.ler.yrmall.dto.LoginUser;
import com.ler.yrmall.enums.ErrorCodeEnum;
import com.ler.yrmall.exception.BusinessException;
import com.ler.yrmall.order.entity.OrderEntity;
import com.ler.yrmall.order.entity.OrderItemEntity;
import com.ler.yrmall.order.enums.PaymentEnum;
import com.ler.yrmall.order.form.OrderFrom;
import com.ler.yrmall.order.form.OrderSubmitForm;
import com.ler.yrmall.order.form.SingleOrderConfirmForm;
import com.ler.yrmall.order.service.OrderItemService;
import com.ler.yrmall.order.service.OrderService;
import com.ler.yrmall.order.vo.MemberOrderItemVO;
import com.ler.yrmall.order.vo.MemberOrderVO;
import com.ler.yrmall.product.api.ProductApi;
import com.ler.yrmall.product.dto.SkuDTO;
import com.ler.yrmall.product.dto.SpuDTO;
import com.ler.yrmall.utils.SecurityUtils;
import com.ler.yrmall.ware.api.WareApi;
import com.ler.yrmall.ware.dto.WareLockDTO;
import com.ler.yrmall.ware.dto.WareOrderItemDTO;
import com.ler.yrmall.order.constant.OrderRedisConstant;
import com.ler.yrmall.order.mapper.OrderMapper;
import com.ler.yrmall.order.vo.OrderConfirmVO;
import com.ler.yrmall.order.vo.OrderCreateVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * @author leron
 */
@Slf4j
@Service
@RocketMQMessageListener(consumerGroup = "order-release-consumer-group", topic = "order.release.order.topic")
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderEntity> implements OrderService, RocketMQListener<String> {

    @DubboReference
    private CartApi cartApi;

    @DubboReference
    private MemberApi memberApi;

    @Resource
    private ThreadPoolExecutor executor;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @DubboReference
    private ProductApi productApi;

    @Resource
    private OrderItemService orderItemService;

    @Resource
    private RocketMQTemplate rocketMqTemplate;

    @DubboReference
    private WareApi wareApi;

    @DubboReference
    private CouponApi couponApi;


    @Override
    public IPage<OrderEntity> find(Form request) {
        return this.page(request.getPage(),Wrappers.<OrderEntity>lambdaQuery().orderByDesc(OrderEntity::getCreateTime));
    }

    @Override
    public void onMessage(String s) {
        OrderEntity orderEntity = JSON.parseObject(s, OrderEntity.class);
        orderEntity.setStatus(OrderEntity.OrderStatus.CANCEL.getCode());
        this.updateById(orderEntity);
        // todo 使用事物消息
    }


    @Override
    public OrderConfirmVO getCartOrderConfirm(Long couponId) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        OrderConfirmVO confirmInfo = new OrderConfirmVO();
        SecurityContext context = SecurityContextHolder.getContext();
        CompletableFuture<Void> address = CompletableFuture.runAsync(() -> {
            SecurityContextHolder.setContext(context);
            Result<MemberReceiveAddressDTO> addressResult = memberApi.getDefaultAddress();
            Assert.isTrue(addressResult.isSuccess(), () -> new RuntimeException(addressResult.getMessage()));
            confirmInfo.setDefaultAddress(addressResult.getData());
        }, executor).exceptionally(e -> {
            log.error("获取收货地址失败", e);
            throw new RuntimeException(e);
        });

        // 获取用户当前购物车中的商品
        CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
            SecurityContextHolder.setContext(context);
            confirmInfo.setItems(BeanUtil.copyToList(getCartConvertOrderLine(), OrderItemEntity.class));
        }, executor).exceptionally(e -> {
            log.error("获取用户购物车失败", e);
            throw new RuntimeException(e);
        });

        try {
            CompletableFuture.allOf(address, cartFuture).get();
        } catch (InterruptedException | ExecutionException e) {
            log.error(e.getMessage());
            throw new RuntimeException(e);
        }

        if (couponId == null) {
            CouponDTO couponDTO = this.computeBestCoupon(confirmInfo.getTotalAmount(), confirmInfo.getItems().stream().map(OrderItemEntity::getSpuId).toArray(Long[]::new));
            if (couponDTO != null) {
                confirmInfo.setCoupon(couponDTO);
            }
        } else {
            CouponDTO coupon = this.getCouponById(couponId);
            confirmInfo.setCoupon(coupon);
        }

        String token = UUID.fastUUID().toString(true);
        confirmInfo.setOrderToken(token);
        stringRedisTemplate.opsForValue()
                .set(OrderRedisConstant.ORDER_TOKEN_PREFIX + loginUser.getId(), token);
        return confirmInfo;
    }

    @Override
    public OrderConfirmVO getSingleOrderConfirm(SingleOrderConfirmForm request) {
        OrderConfirmVO confirmInfo = new OrderConfirmVO();
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Result<MemberReceiveAddressDTO> addressResult = memberApi.getDefaultAddress();
        Assert.isTrue(addressResult.isSuccess(), () -> new RuntimeException(addressResult.getMessage()));

        Result<SkuDTO> skuResponse = productApi.getSkuById(request.getSkuId());
        Assert.isTrue(skuResponse.isSuccess(), () -> new BusinessException(ErrorCodeEnum.SKU_LOSE));
        SkuDTO sku = skuResponse.getData();

        Result<SpuDTO> spuResponse = productApi.getSpuById(sku.getSpuId());
        Assert.isTrue(skuResponse.isSuccess(), () -> new BusinessException(ErrorCodeEnum.SKU_LOSE));
        SpuDTO spu = spuResponse.getData();

        Result<List<String>> attrResponse = productApi.getAttrsAsString(request.getSkuId());
        Assert.isTrue(attrResponse.isSuccess(), () -> new BusinessException(ErrorCodeEnum.SKU_LOSE));

        OrderItemEntity item = new OrderItemEntity();
        item.setSpuId(sku.getSpuId());
        item.setSpuName(spu.getName());
        item.setSpuPic(spu.getMainImg());
        item.setSkuId(request.getSkuId());
        item.setSkuAttrsVals(String.join(";", attrResponse.getData()));
        item.setSkuName(sku.getName());
        item.setSkuPic(sku.getCover());
        item.setSkuPrice(sku.getPrice());
        item.setSkuQuantity(request.getNum());
        confirmInfo.setTotalAmount(sku.getPrice().multiply(BigDecimal.valueOf(request.getNum())));
        String token = UUID.fastUUID().toString(true);
        confirmInfo.setOrderToken(token);
        confirmInfo.setItems(Collections.singletonList(item));
        confirmInfo.setDefaultAddress(addressResult.getData());

        if (request.getCouponId() == null) {
            CouponDTO couponDTO = this.computeBestCoupon(confirmInfo.getTotalAmount(), confirmInfo.getItems().stream().map(OrderItemEntity::getSpuId).toArray(Long[]::new));
            if (couponDTO != null) {
                confirmInfo.setCoupon(couponDTO);
            }
        } else {
            CouponDTO coupon = this.getCouponById(request.getCouponId());
            confirmInfo.setCoupon(coupon);
        }

        stringRedisTemplate.opsForValue()
                .set(OrderRedisConstant.ORDER_TOKEN_PREFIX + loginUser.getId(), token);
        return confirmInfo;
    }

    private CouponDTO computeBestCoupon(BigDecimal amount,Long ...spuId) {
        Result<CouponDTO> response = couponApi.computeBestCoupon(Arrays.asList(spuId), amount);
        Assert.isTrue(response.isSuccess(),() -> new BusinessException(ErrorCodeEnum.CLIENT_DEFAULT_ERROR));
        return response.getData();
    }

    private CouponDTO getCouponById(Long couponId) {
        Result<CouponDTO> response = couponApi.getCouponById(couponId);
        Assert.isTrue(response.isSuccess(),() -> new BusinessException(ErrorCodeEnum.CLIENT_DEFAULT_ERROR));
        return response.getData();
    }


    // TODO 保证消息一定会发送出去，每一个消息都可以做好日志记录（给数据库保存每一个消息的详细信息)
    // TODO 定期扫描数据库将失败的消息再发送—遍

    /**
     * @param request
     * @return
     * @GlobalTransactional seata默认使用 AT 模式，此模式会上很多的锁，不适合高并发的操作
     * 可以发送消息让库存服务自动解锁 下单 -> 扣减库存 -> 发送延迟消息 -> ware服务收到消息 -> 检查订单状态决定是否解锁
     * 另外库存服务设置定时任务定时检查订单状态并释放相应的库存
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderEntity submit(OrderSubmitForm request) {
        //验证令牌
        String token = request.getOrderToken();
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Long cheek = stringRedisTemplate.execute(new DefaultRedisScript<>(script, Long.class),
                Collections.singletonList(OrderRedisConstant.ORDER_TOKEN_PREFIX + SecurityUtils.getLoginUser().getId()), token);
        if (cheek != null && cheek == 0L) {
            throw new BusinessException(ErrorCodeEnum.ORDER_TOKEN_LOSE);
        } else {
            // 验证通过
            //1、创建订单，订单项等信息
            OrderCreateVO order = createOrder(request);
            // 保存订单
            saveOrder(order, request);
            // 锁定库存
            WareLockDTO wareLock = new WareLockDTO();
            wareLock.setOrderSn(order.getOrder().getOrderSn());
            List<WareOrderItemDTO> itemVos = order.getOrderLines().stream().map(item -> {
                WareOrderItemDTO orderItemVo = new WareOrderItemDTO();
                orderItemVo.setCount(item.getSkuQuantity());
                orderItemVo.setSkuId(item.getSkuId());
                orderItemVo.setTitle(item.getSkuName());
                return orderItemVo;
            }).collect(Collectors.toList());
            wareLock.setOrders(itemVos);
            Result<?> result = wareApi.orderLock(wareLock);
            // 多个订单项代表购物车下单 删除购物车中的商品
            List<OrderItemEntity> lines = order.getOrderLines();
            if (lines.size() > 1) {
                List<Long> skuIds = lines.stream().map(OrderItemEntity::getSkuId).collect(Collectors.toList());
                // 删除购物车的商品 忽略报错
                executor.submit(() -> cartApi.delete(skuIds));
            }
            if (result.isSuccess()) {
                // 发布订单创建消息 30分钟自动解锁
                Message<OrderEntity> message = MessageBuilder.withPayload(order.getOrder()).build();
                //
                rocketMqTemplate.syncSend("order_topic:create", message, 3000, 16);
                return BeanUtil.copyProperties(order.getOrder(), OrderEntity.class);
            } else {
                throw new BusinessException(result.getMessage());
            }
        }

    }

    @Override
    public OrderEntity getOrderByOrderSn(String orderSn) {
        return this.getOne(Wrappers.<OrderEntity>lambdaQuery().eq(OrderEntity::getOrderSn, orderSn));
    }

    @Override
    public void closeOrder(OrderEntity order) {
        OrderEntity o = this.getOrderByOrderSn(order.getOrderSn());
        if (o == null) {
            return;
        }
        if (OrderEntity.OrderStatus.NON_PAY.getCode().equals(o.getStatus())) {
            o.setStatus(OrderEntity.OrderStatus.CANCEL.getCode());
            this.updateById(o);
        }
    }

    private OrderCreateVO createOrder(OrderSubmitForm submitForm) {

        OrderCreateVO createTo = new OrderCreateVO();

        String orderSn = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + RandomUtil.randomNumbers(6);

        OrderEntity orderEntity = buildOrder(orderSn, submitForm);

        // todo 此处 orderItem 需要重新赋值
        List<OrderItemEntity> orderItems = submitForm.getItems();

        List<Long> skuIds = orderItems.stream().map(OrderItemEntity::getSkuId).collect(Collectors.toList());
        List<Long> spuIds = orderItems.stream().map(OrderItemEntity::getSpuId).collect(Collectors.toList());
        Result<List<SkuDTO>> skuListResponse = productApi.listSkuByIds(skuIds);
        Assert.isTrue(skuListResponse.isSuccess(), () -> new BusinessException(ErrorCodeEnum.SKU_LOSE));
        Assert.isTrue(Objects.equals(skuIds.size(), skuListResponse.getData().size()), () -> new BusinessException(ErrorCodeEnum.SKU_LOSE));

        Result<List<SpuDTO>> spuListResponse = productApi.listSpuByIds(spuIds);
        Assert.isTrue(spuListResponse.isSuccess(), () -> new BusinessException(ErrorCodeEnum.SKU_LOSE));

        Map<Long, SkuDTO> skuMap = skuListResponse.getData().stream().collect(Collectors.toMap(SkuDTO::getId, Function.identity()));
        Map<Long, SpuDTO> spuMap = spuListResponse.getData().stream().collect(Collectors.toMap(SpuDTO::getId, Function.identity()));

        orderItems.forEach(item -> {
            SkuDTO sku = skuMap.get(item.getSkuId());
            SpuDTO spu = spuMap.get(item.getSpuId());
            Assert.isTrue(spu != null, () -> new BusinessException(ErrorCodeEnum.SKU_LOSE));
            item.setSkuId(sku.getId());
            item.setSpuId(sku.getSpuId());
            item.setSkuName(sku.getName());
            item.setSkuPic(sku.getCover());
            item.setSkuPrice(sku.getPrice());
            item.setSkuPrice(sku.getPrice());
            item.setTotalAmount(sku.getPrice().multiply(BigDecimal.valueOf(item.getSkuQuantity())));
            item.setSpuId(spu.getId());
            item.setSpuName(spu.getName());
            item.setSpuPic(spu.getMainImg());
            // 优惠信息 todo
            // 积分信息 todo
            // 订单项的价格信息
            BigDecimal subtract = item.getTotalAmount().subtract(Optional.ofNullable(item.getCouponAmount()).orElse(BigDecimal.ZERO))
                    .subtract(Optional.ofNullable(item.getIntegrationAmount()).orElse(BigDecimal.ZERO));
            item.setRealAmount(subtract);
        });

        orderItems.forEach(item -> item.setOrderSn(orderSn));

        computePrice(orderEntity, orderItems);

        createTo.setOrder(orderEntity);
        createTo.setOrderLines(orderItems);
        return createTo;
    }

    private void saveOrder(OrderCreateVO createVo, OrderSubmitForm submitForm) {
        OrderEntity order = createVo.getOrder();
        OrderEntity orderEntity = new OrderEntity();
        BeanUtils.copyProperties(order, orderEntity);
        this.save(orderEntity);

        List<OrderItemEntity> orderItems = createVo.getOrderLines();

        List<OrderItemEntity> items = submitForm.getItems();
        Map<Long, OrderItemEntity> skuMap = items.stream().collect(Collectors.toMap(OrderItemEntity::getSkuId, Function.identity()));

        orderItems.forEach(item -> {
            OrderItemEntity target = new OrderItemEntity();
            BeanUtils.copyProperties(item, target);
            target.setOrderId(orderEntity.getId());
            target.setRemark(skuMap.get(item.getSkuId()).getRemark());
            orderItemService.save(target);
        });
    }


    private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> orderLines) {

        BigDecimal total = BigDecimal.ZERO;
        BigDecimal integration = BigDecimal.ZERO;
        BigDecimal payAmount = BigDecimal.ZERO;

        int gift = 0;
        int growth = 0;
        //订单的总额，叠加每一个订单项的总额信息
        for (OrderItemEntity line : orderLines) {
            integration = integration.add(Optional.ofNullable(line.getIntegrationAmount()).orElse(BigDecimal.ZERO));
            total = total.add(line.getTotalAmount());
            payAmount = payAmount.add(line.getRealAmount());
            gift += Optional.ofNullable(line.getGiftIntegration()).orElse(0);
            growth += Optional.ofNullable(line.getGiftGrowth()).orElse(0);
        }
        //1、订单价格相关
        orderEntity.setTotalAmount(total);
        //应付总额
        if (orderEntity.getCouponId() != null) {
            Result<CouponDTO> response = couponApi.useCoupon(orderEntity.getCouponId(), orderEntity.getTotalAmount());
            Assert.isTrue(response.isSuccess(),() -> new BusinessException(ErrorCodeEnum.COUPON_DISABLED));
            BigDecimal couponAmount = response.getData().getAmount();
            orderEntity.setCouponAmount(couponAmount);
            payAmount = payAmount.subtract(couponAmount);
        }
        orderEntity.setPayAmount(payAmount);
        orderEntity.setIntegrationAmount(integration);

        //设置积分等信息
        orderEntity.setIntegration(gift);
        orderEntity.setGrowth(growth);
    }

    /**
     * 构建订单信息
     *
     * @param orderSn
     * @return
     */
    private OrderEntity buildOrder(String orderSn, OrderSubmitForm submitForm) {
        OrderEntity entity = new OrderEntity();
        entity.setOrderSn(orderSn);
        entity.setMemberId(SecurityUtils.getLoginUser().getId());
        entity.setMemberUsername(SecurityUtils.getLoginUser().getUsername());
        entity.setCouponId(submitForm.getCouponId());
        entity.setStatus(OrderEntity.OrderStatus.NON_PAY.getCode());

        //根据信息获取收货地址
        Result<MemberReceiveAddressDTO> addressResult = memberApi.getMemberAddress(submitForm.getAddressId());
        Assert.isTrue(addressResult.isSuccess(), () -> new RuntimeException(addressResult.getMessage()));
        MemberReceiveAddressDTO address = addressResult.getData();

        entity.setReceiverName(address.getName());
        entity.setReceiverPhone(address.getPhone());
        entity.setReceiverPostCode(address.getPostCode());
        entity.setReceiverProvince(address.getProvince());
        entity.setReceiverCity(address.getCity());
        entity.setReceiverRegion(address.getRegion());
        entity.setReceiverDetailAddress(address.getDetailAddress());
        return entity;
    }


    private List<OrderItemEntity> getCartConvertOrderLine() {
        Result<CartDTO> cartResult = cartApi.getCart();
        Assert.isTrue(cartResult.isSuccess(), () -> new BusinessException(ErrorCodeEnum.CLIENT_DEFAULT_ERROR));
        CartDTO cart = cartResult.getData();
        List<Long> skuIds = cart.getItems().stream().map(CartItemDTO::getSkuId).collect(Collectors.toList());
        List<Long> spuIds = cart.getItems().stream().map(CartItemDTO::getSpuId).collect(Collectors.toList());
        Result<List<SkuDTO>> skuListResponse = productApi.listSkuByIds(skuIds);
        Assert.isTrue(skuListResponse.isSuccess(), () -> new BusinessException(ErrorCodeEnum.SKU_LOSE));
        Assert.isTrue(Objects.equals(skuIds.size(), skuListResponse.getData().size()), () -> new BusinessException(ErrorCodeEnum.SKU_LOSE));

        Result<List<SpuDTO>> spuListResponse = productApi.listSpuByIds(spuIds);
        Assert.isTrue(spuListResponse.isSuccess(), () -> new BusinessException(ErrorCodeEnum.SKU_LOSE));

        Map<Long, SkuDTO> skuMap = skuListResponse.getData().stream().collect(Collectors.toMap(SkuDTO::getId, Function.identity()));
        Map<Long, SpuDTO> spuMap = spuListResponse.getData().stream().collect(Collectors.toMap(SpuDTO::getId, Function.identity()));

        return cart.getItems().stream().filter(CartItemDTO::getChecked).map(item -> {
            SkuDTO sku = skuMap.get(item.getSkuId());
            SpuDTO spu = spuMap.get(item.getSpuId());
            Assert.isTrue(spu != null, () -> new BusinessException(ErrorCodeEnum.SKU_LOSE));
            OrderItemEntity orderItem = new OrderItemEntity();
            orderItem.setSkuId(sku.getId());
            orderItem.setSpuId(sku.getSpuId());
            orderItem.setSkuName(sku.getName());
            orderItem.setSkuPic(sku.getCover());
            orderItem.setSkuAttrsVals(String.join(";", item.getSkuAttr()));
            orderItem.setSkuPrice(sku.getPrice());
            orderItem.setSkuQuantity(item.getCount());
            orderItem.setSkuPrice(sku.getPrice());
            orderItem.setTotalAmount(sku.getPrice().multiply(BigDecimal.valueOf(item.getCount())));
            orderItem.setSpuId(spu.getId());
            orderItem.setSpuName(spu.getName());
            orderItem.setSpuPic(spu.getMainImg());
            //4、优惠信息 todo
            //5、积分信息 todo
            //6、订单项的价格信息
            BigDecimal subtract = orderItem.getTotalAmount().subtract(Optional.ofNullable(orderItem.getCouponAmount()).orElse(BigDecimal.ZERO))
                    .subtract(Optional.ofNullable(orderItem.getIntegrationAmount()).orElse(BigDecimal.ZERO));
            orderItem.setRealAmount(subtract);
            return orderItem;
        }).collect(Collectors.toList());
    }

    @Override
    public void createSeckillOrder(SeckillOrderDTO seckillOrder) {
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setMemberId(seckillOrder.getMemberId());
        orderEntity.setOrderSn(seckillOrder.getOrderNo());
//        orderEntity.setMemberUsername(SecurityUtils.getLoginUser().getUsername());
        orderEntity.setTotalAmount(seckillOrder.getSeckillPrice().multiply(BigDecimal.valueOf(seckillOrder.getNum())));
        orderEntity.setPayAmount(seckillOrder.getSeckillPrice());
        orderEntity.setStatus(0);
        // todo 收获地址
//        Result<List<MemberReceiveAddressDTO>> addressResponse = memberApi.getAddressList();
//        MemberReceiveAddressDTO address = addressResponse.getData().get(0);
//        orderEntity.setReceiverName(address.getName());
//        orderEntity.setReceiverPhone(address.getPhone());
//        orderEntity.setReceiverPostCode(address.getPostCode());
//        orderEntity.setReceiverProvince(address.getProvince());
//        orderEntity.setReceiverCity(address.getCity());
//        orderEntity.setReceiverRegion(address.getRegion());
//        orderEntity.setReceiverDetailAddress(address.getDetailAddress());
        this.save(orderEntity);

        Result<SkuDTO> skuResponse = productApi.getSkuById(seckillOrder.getSkuId());

        Result<SpuDTO> spuResponse = productApi.getSpuById(skuResponse.getData().getSpuId());

        OrderItemEntity itemEntity = new OrderItemEntity();
        itemEntity.setOrderId(orderEntity.getId());
        itemEntity.setOrderSn(orderEntity.getOrderSn());
        itemEntity.setSpuId(spuResponse.getData().getId());
        itemEntity.setSpuName(spuResponse.getData().getName());
        itemEntity.setSkuId(seckillOrder.getSkuId());
        itemEntity.setSkuName(skuResponse.getData().getName());
        itemEntity.setSkuPic(skuResponse.getData().getCover());
        itemEntity.setSkuPrice(skuResponse.getData().getPrice());
        itemEntity.setSkuQuantity(seckillOrder.getNum());
        itemEntity.setRealAmount(seckillOrder.getSeckillPrice());
        orderItemService.save(itemEntity);
    }

    @Override
    public IPage<MemberOrderVO> memberOrder(OrderFrom request) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Page<OrderEntity> orders = this.page(request.getPage(), Wrappers.<OrderEntity>lambdaQuery()
                .eq(OrderEntity::getMemberId, loginUser.getId())
                .eq(request.getStatus() != null, OrderEntity::getStatus, request.getStatus())
                .orderByDesc(OrderEntity::getCreateTime));
        List<Long> orderIds = orders.getRecords().stream().map(OrderEntity::getId).collect(Collectors.toList());
        Map<Long, List<OrderItemEntity>> lineMap = orderItemService.list(Wrappers.<OrderItemEntity>lambdaQuery().in(OrderItemEntity::getOrderId, orderIds))
                .stream().collect(Collectors.groupingBy(OrderItemEntity::getOrderId));
        return orders.convert(item -> {
            MemberOrderVO mo = BeanUtil.copyProperties(item, MemberOrderVO.class);
            List<OrderItemEntity> lines = lineMap.get(item.getId());
            if (lines != null) {
                List<MemberOrderItemVO> collect = lines.stream().map(line -> {
                    MemberOrderItemVO target = BeanUtil.copyProperties(line, MemberOrderItemVO.class);
                    target.setStatusText(OrderEntity.OrderStatus.translate(line.getStatus()));
                    return target;
                }).collect(Collectors.toList());
                mo.setOrderLines(collect);
            }
            mo.setStatusText(OrderEntity.OrderStatus.translate(item.getStatus()));
            return mo;
        });
    }

    @Override
    public BigDecimal getTradeAmount() {
        return this.baseMapper.getTradeAmount();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void simulatePay(Integer payWay, String orderSn) {
        OrderEntity order = this.getOrderByOrderSn(orderSn);
        if (!order.getStatus().equals(OrderEntity.OrderStatus.NON_PAY.getCode())) {
            throw new BusinessException("该订单已支付");
        }
        order.setStatus(OrderEntity.OrderStatus.WAIT_DELIVER.getCode());
        order.setPayType(PaymentEnum.getByCode(payWay).getCode());
        order.updateById();
        orderItemService.update(Wrappers.<OrderItemEntity>lambdaUpdate()
                .set(OrderItemEntity::getStatus,OrderEntity.OrderStatus.WAIT_DELIVER.getCode())
                .eq(OrderItemEntity::getOrderSn,orderSn));
    }
}